﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Sinacor.Servico.Infra.FileTransfer.BusinessEntity;
using System.Configuration;
using System.Collections.Specialized;
using Ionic.Zip;
using PSE.Framework.Configuration;

namespace Sinacor.Servico.Infra.FileTransfer.BusinessLogic
{
    public class FileRepository
    {
        public FileInfoEntity DownloadFile(FileInfoEntity request)
        {
            FileInfoEntity result = null;

            string filePath = Path.Combine(GetDirectoryFolder(request.ProcessName, FolderLocation.Download), request.FileName);

			if (File.Exists(filePath))
			{
				string path = filePath;

				// Comprime o arquivo antes de enviar
				if (request.CompressionBehavior == CompressionBehavior.Compress ||
					request.CompressionBehavior == CompressionBehavior.DeliverCompressed)
				{
					using (ZipFile zipFile = new ZipFile())
					{
						path = Path.GetTempFileName();
						if (File.Exists(path)) File.Delete(path);

						zipFile.AddFile(filePath, "");
						zipFile.Save(path);
					}
				}

				FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);

				result = new FileInfoEntity();
				result.FileName = request.FileName;
				result.DataStream = stream;
			}
			else
			{
				throw new FileNotFoundException("The informed file was not found '" + filePath + "'");
			}

            return result;
        }

        public void UploadFile(FileInfoEntity request)
        {
            const int bufferSize = 20480;
            byte[] buffer = new byte[bufferSize];
            int bytes = 0;

            string directoryFolder = GetDirectoryFolder(request.ProcessName, FolderLocation.Upload);
            string filePath = Path.Combine(directoryFolder, request.FileName);

            if (!Directory.Exists(directoryFolder)) Directory.CreateDirectory(directoryFolder);

            string path = filePath;

            if (request.CompressionBehavior == CompressionBehavior.Compress)
            {
                path = Path.GetTempFileName();
            }
            else if (request.CompressionBehavior == CompressionBehavior.DeliverCompressed)
            {
                path = Path.ChangeExtension(filePath, "zip");
            }

            if (File.Exists(path)) File.Delete(path);

            using (FileStream writeStream = new FileStream(path, FileMode.CreateNew, FileAccess.Write))
            {
                while ((bytes = request.DataStream.Read(buffer, 0, bufferSize)) > 0)
                {
                    writeStream.Write(buffer, 0, bytes);
                }
            }

            if (request.CompressionBehavior == CompressionBehavior.Compress)
            {
                if (File.Exists(filePath)) File.Delete(filePath);

                using (ZipFile zipFile = ZipFile.Read(path))
                {
                    zipFile[0].Extract(Path.GetTempPath(), ExtractExistingFileAction.OverwriteSilently);
                    File.Move(Path.Combine(Path.GetTempPath(), zipFile[0].FileName), filePath);
                }
            }
        }

        public void DeleteFile(FileInfoEntity request)
        {
            string filePath = Path.Combine(GetDirectoryFolder(request.ProcessName, request.FolderLocation), request.FileName);

            if (File.Exists(filePath))
                File.Delete(filePath);
        }

        public List<FileInfoEntity> ListFiles(FileInfoEntity request)
        {
            List<FileInfoEntity> list = new List<FileInfoEntity>();
            string basePath = GetDirectoryFolder(request.ProcessName, request.FolderLocation);

            if (Directory.Exists(basePath))
            {
                DirectoryInfo dirInfo = new DirectoryInfo(basePath);
                FileInfo[] files = dirInfo.GetFiles("*.*", SearchOption.AllDirectories);

                list = (from f in files
                        select new FileInfoEntity()
                        {
                            Size = f.Length,
                            FileName = Path.GetFileName(f.FullName)
                        }).ToList<FileInfoEntity>();
            }

            return list;
        }

        private string GetDirectoryFolder(string processName, FolderLocation folderLocation)
        {
            string processRootPath = Path.Combine(ApplicationConfiguration.GetApplicationRootDirectory(), ConfigurationManager.AppSettings["ProcessesFolderName"]);

            string path = Path.Combine(
                                processRootPath,
                                Path.Combine(
                                    processName.Replace(".", "\\"),
                                    ConfigurationManager.AppSettings[folderLocation == FolderLocation.Upload ? "UploadDirectoryName" : "DownloadDirectoryName"]
                                )
                            );

            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            return path;
        }
    }
}
